package com.swipemaster.network;

import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.net.ConnectivityManager;

import com.swipemaster.common.Global;
import com.swipemaster.record.IntegerRecord;
import com.swipemaster.record.Record;
import com.swipemaster.record.RecordId;
import com.swipemaster.record.Records;
import com.swipemaster.record.RecordsManager;

public class Network
{
	private final static String BASE_URL = "http://swipemaster.vxm.pl/php/";
	private final static String GET_RECORDS_PAGE = "selectRecords.php";
	private final static String WEAKEST_PAGE = "getWeakest.php";
	private final static String INSERT_RECORD_PAGE = "insertRecord.php";
	private final static String STATISTICS_PAGE = "sendStats.php";

	public static ArrayList<WorldRecord> getWorldRecords(RecordId recordId, int offset, int howMany) throws Exception
	{
		final ArrayList<NameValuePair> nameValuePairs = getSelectPairs(recordId, offset, howMany);
		final String result = doHttpPost(GET_RECORDS_PAGE, nameValuePairs);
		final ArrayList<WorldRecord> records = new ArrayList<WorldRecord>();
		try
		{
			final JSONArray jsonArray = new JSONArray(result);
			for (int i = 0; i < jsonArray.length(); i++)
			{
				final JSONObject json = jsonArray.getJSONObject(i);
				records.add(new WorldRecord(json));
			}
		}
		catch (final JSONException e)
		{
			e.printStackTrace();
		}
		return records;
	}

	public static boolean isConnected()
	{
		final ConnectivityManager manager = (ConnectivityManager) Global.app
				.getSystemService(Context.CONNECTIVITY_SERVICE);
		return manager.getActiveNetworkInfo() != null;
	}

	public static boolean isWorldRecord(Record newRecord) throws Exception
	{
		final ArrayList<NameValuePair> nameValuePairs = getPositionPairs(newRecord);
		final String result = doHttpPost(WEAKEST_PAGE, nameValuePairs);
		if (result.equals(""))
		{
			return true;
		}
		final JSONObject object = new JSONObject(result);
		final WorldRecord worldRecord = new WorldRecord(object);
		final Record weakestRecord = newRecord.clone(worldRecord);
		return newRecord.isBetter(weakestRecord);
	}

	public static int sendRecord(Record record, String username) throws Exception
	{
		final ArrayList<NameValuePair> nameValuePairs = getSendPairs(record, username);
		final String result = doHttpPost(INSERT_RECORD_PAGE, nameValuePairs);
		final JSONObject object = new JSONObject(result);
		return object.getInt("rank");
	}

	public static void sendStats() throws Exception
	{
		final ArrayList<NameValuePair> nameValuePairs = getStatsPairs();
		doHttpPost(STATISTICS_PAGE, nameValuePairs);
	}

	/** Sends HTTP POST to the given page.
	 * @param page Name of PHP script on remote server.
	 * @param pairs Data passed with POST.
	 * @return String for reading the HTTP response.
	 * @throws Exception It's safer to throw all the exceptions, since we can handle them with no problem, user will not
	 * die without global high scores. */
	private static String doHttpPost(String page, ArrayList<NameValuePair> pairs) throws Exception
	{
		final HttpClient httpclient = new DefaultHttpClient();
		final HttpPost httpPost = new HttpPost(BASE_URL + page);
		httpPost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
		httpPost.setEntity(new UrlEncodedFormEntity(pairs, "UTF-8"));
		final HttpResponse response = httpclient.execute(httpPost);
		final HttpEntity entity = response.getEntity();
		return EntityUtils.toString(entity, "UTF-8");
	}

	private static ArrayList<NameValuePair> getPositionPairs(Record record)
	{
		final ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();
		pairs.add(new BasicNameValuePair("type", record.recordId.getId() + ""));
		if (record.getType() == RecordId.LEVEL)
		{
			pairs.add(new BasicNameValuePair("is_puzzle",
					RecordsManager.getInfo(record.recordId.getLevelIndex()).isPuzzle + ""));
		}
		return pairs;
	}

	private static ArrayList<NameValuePair> getSelectPairs(RecordId recordId, int offset, int howMany)
	{
		final ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();
		pairs.add(new BasicNameValuePair("type", recordId.getId() + ""));
		pairs.add(new BasicNameValuePair("position", offset + ""));
		pairs.add(new BasicNameValuePair("how_many", howMany + ""));
		if (recordId.getType() == RecordId.LEVEL)
		{
			pairs.add(new BasicNameValuePair("is_puzzle", RecordsManager.getInfo(recordId.getLevelIndex()).isPuzzle
					+ ""));
		}
		return pairs;
	}

	private static ArrayList<NameValuePair> getSendPairs(Record record, String username)
	{
		final String recordType = record.recordId.getId() + "";
		final String recordString = record.getRecordStringForPHP();
		final String hash = Security.getHash(recordType, username, recordString);

		final ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();
		pairs.add(new BasicNameValuePair("type", recordType));
		pairs.add(new BasicNameValuePair("username", username));
		pairs.add(new BasicNameValuePair("user_id", Security.getUserId() + ""));
		pairs.add(new BasicNameValuePair("record", recordString));
		pairs.add(new BasicNameValuePair("hash", hash));

		if (record.getType() == RecordId.LEVEL)
		{
			final String puzzleString = RecordsManager.getInfo(record.recordId.getLevelIndex()).isPuzzle + "";
			pairs.add(new BasicNameValuePair("is_puzzle", puzzleString));
		}

		return pairs;
	}

	private static ArrayList<NameValuePair> getStatsPairs()
	{
		final Records records = RecordsManager.getRecords();
		final ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();
		final String userId = Security.getUserId() + "";
		pairs.add(new BasicNameValuePair("user_id", userId));
		pairs.add(new BasicNameValuePair("games_played",
				((IntegerRecord) records.getRecord(RecordId.GAMES_PLAYED)).counter + ""));
		pairs.add(new BasicNameValuePair("custom_games_played", ((IntegerRecord) records
				.getRecord(RecordId.CUSTOM_GAMES_PLAYED)).counter + ""));
		pairs.add(new BasicNameValuePair("challenge_games_played", ((IntegerRecord) records
				.getRecord(RecordId.CHALLENGE_GAMES_PLAYED)).counter + ""));
		pairs.add(new BasicNameValuePair("level_games_played", ((IntegerRecord) records
				.getRecord(RecordId.LEVEL_GAMES_PLAYED)).counter + ""));
		pairs.add(new BasicNameValuePair("stars", ((IntegerRecord) records.getRecord(RecordId.STARS)).counter + ""));
		pairs.add(new BasicNameValuePair("levels_completed", RecordsManager.getNumberOfCompletedLevels() + ""));

		final String hash = Security.getHash(userId);
		pairs.add(new BasicNameValuePair("hash", hash));

		return pairs;
	}
}
